import { Router } from "express";
import path from "path";
import fs from "fs";
import { getErr } from "../middleware/getSendResult";
import { CODE, staticPath } from "@/utils/const";
import type { request, response } from "../../interface/type";
import { Base64 } from "js-base64"
import { MyFileDir } from "@/model/init";
import { MyFileDirItf } from "@/interface/interface";
const router = Router();

// contenttype的枚举
enum ContentTypeEnum {
    ".bmp" = "image/bmp",
    ".jpg" = "image/jpeg",
    ".jpeg" = "image/jpeg",
    ".png" = "image/png",
    ".gif" = "image/gif",
    ".svg" = "image/svg+xml",
    ".avi" = "video/avi",
    ".rmvb" = "application/vnd.rn-realmedia-vbr / application/vnd.rn-realmedia / application/x-pn-realaudio / application/smil",
    ".rm" = "application/vnd.rn-realmedia-vbr / application/vnd.rn-realmedia / application/x-pn-realaudio / application/smil",
    ".asf" = "video/x-ms-asf",
    ".divx" = "video/divx",
    ".mpg" = "video/mpeg",
    ".mpeg" = "video/mpeg",
    ".mpe" = "video/mpeg",
    ".wmv" = "video/x-ms-wmv",
    ".mp4" = "video/mp4",
    ".mkv" = "video/x-matroska",
    ".vob" = "video/x-ms-vob",
    ".ts" = "video/mp2t",
    ".flv" = "video/x-flv",
    ".mov" = "video/quicktime",
    ".webm" = "video/quicktime",
}

/**
 * @description: 普通下载 直接把文件整体传递给前端
 * @param {request} req
 * @param {response} res
 * @return {*}
 * @author: tao wenbo 2419421809@qq.com
 */
async function commonDownload(req: request, res: response) {
    const filePath = path.join(staticPath, req.query.path as string);
    const filename = path.basename(filePath);
    const ext = path.extname(filePath).toLowerCase();
    try {
        const stat = await fs.promises.stat(filePath);
        res.setHeader("Content-Disposition", `attachment; filename=${filename}`);
        res.setHeader("Content-Type", (ContentTypeEnum as any)[ext]);
        res.setHeader("Content-Length", stat.size);
        const stream = fs.createReadStream(filePath);
        stream.pipe(res);
    } catch (error) {
        res.send(getErr("下载失败，无法读取到该文件", CODE.errorCode));
    }
}


/**
 * @description: 分段下载主函数
 * @param {request} req
 * @param {response} res
 * @return {*}
 * @author: tao wenbo 2419421809@qq.com
 */
async function rangeDownload(req: request, res: response) {
    let id = req.query.id
    const file = await getFileById(Number(id))
    const filePath = path.join(staticPath, file.path);

    // 如果文件不存在，则返回 404 错误
    if (!fs.existsSync(filePath)) {
        res.status(404).send("文件不存在");
        return;
    }

    // 获取文件状态信息
    const stat = fs.statSync(filePath);

    // 计算文件大小和片段范围
    const fileSize = stat.size;
    const range = req.headers.range;

    // 如果没有设置范围，则默认返回整个文件内容
    if (!range) {
        res.status(200).header({
            "Content-Disposition": `attachment; filename=${Base64.encode(path.basename(filePath))}`,
            "Content-Type": "application/octet-stream",
            "Content-Length": fileSize,
        });

        const readStream = fs.createReadStream(filePath);
        readStream.pipe(res);
        return;
    }

    // 解析范围参数（比如 "bytes=0-1000"）
    const positions = range.replace(/bytes=/, "").split("-");
    const start = parseInt(positions[0], 10);
    let end = positions[1] ? parseInt(positions[1], 10) : fileSize - 1;
    // 是否是最后一个分块
    let isLast = false;
    // 最后一个分段的end可能大于了文件的大小，这样会报错
    if( end >= fileSize ){
        end = fileSize - 1
        isLast = true
    }
    // 计算片段大小
    const chunkSize = end - start + 1;
    // 如果是最后一个分段就需要设置相应status为200否则用206表示分段传递成功
    if( isLast ){
        res.status( 200 )
    }else{
        res.status( 206 )
    }

    // 设置 Content-Range 头信息，告诉客户端文件的部分内容
    res.header({
        "Content-Disposition": `attachment; filename=${Base64.encode(path.basename(filePath))}`,
        "Content-Type": "application/octet-stream",
        "Content-Length": chunkSize,
        "Content-Range": `bytes ${start}-${end}/${fileSize}`,
    });
    

    // 使用 fs.createReadStream() 创建一个可读流，然后调用 stream.pipe() 方法将可读流的片段写到可写流中
    const readStream = fs.createReadStream(filePath, { start, end });
    readStream.pipe(res);
}



/**
 * @description: 通过id得到文件在数据库中的信息
 * @param {number} id
 * @return {*}
 * @author: tao wenbo 2419421809@qq.com
 */
async function getFileById(id:number) {
    let file = await MyFileDir.findByPk( id )
    return file?.dataValues as MyFileDirItf
}

/**
 * @description: 得到文件大小和名字
 * @param {request} req
 * @param {response} res
 * @return {*}
 * @author: tao wenbo 2419421809@qq.com
 */
async function getFileSizeAndName(req: request, res: response){
    const file = await getFileById(Number(req.headers.id))
    const filePath = path.join(staticPath, file.path);
    try{
        const stat = await fs.promises.stat(filePath);
        // 设置响应头，传递文件大小和文件名
        res.set('Content-Length', '' + stat.size ).set("filename", Base64.encode(path.basename(filePath))).end(); 
    }catch(err){
        console.log(err);
        res.status(404).end()
    }
}





router.head( "/range", getFileSizeAndName )

router.get("/range", rangeDownload);

// 普通下载
router.get("", commonDownload);

export default router;
